<template>
  <view class="content" :class="[tableHeight != 'auto' ? 'fix-height' : '']">
    <view class="table_box_big" :style="{ height: tableHeight }">
      <view class="table_box">
        <!-- 头部内容 【-->
        <view class="div-table div-table-head">
          <view class="thead">
            <view class="tr">
              <view
                class="td selection"
                v-if="selection == 'mulit'"
                :style="{ width: selectionTdWidth, height: thTdHeight + 'px' }">
                <view
                  :class="['td_wrap']"
                  :style="{
                    width: selectionTdWidth,
                    height: thTdHeight + 'px',
                  }">
                  <checkbox-group @change="checkboxChangeAll">
                    <checkbox
                      value="all"
                      :checked="switchAllCheckBox"
                      style="transform: scale(0.7)" />
                  </checkbox-group>
                </view>
              </view>
              <view
                class="td"
                :style="{
                  width: countHeadColspanWidth(item, index),
                  height: thTdHeight + 'px',
                }"
                v-for="(item, index) in columns"
                :key="item.key">
                <view
                  class="td_wrap"
                  :style="{
                    width: countHeadColspanWidth(item, index, true),
                    height: thTdHeight + 'px',
                  }">
                  {{ item.title }}
                </view>
              </view>
            </view>
          </view>
        </view>
        <!-- 头部内容 】-->
        <!-- 有数据情况 -->
        <template v-if="list.length">
          <view class="table_tbody_box" :style="{ height: talbeBodyHeight }">
            <view class="div-table div-table-body">
              <checkbox-group @change="checkboxChange">
                <template v-for="(item, index) in list">
                  <view
                    :class="[
                      'tr',
                      rowClassNamePlus(item, index),
                      selection == 'single' && checkBoxList[index].$checked
                        ? 'selected'
                        : '',
                      selection == 'single' && checkBoxList[index].$disabled
                        ? 'disabled'
                        : '',
                    ]"
                    @click="selectRow(item, index)"
                    :key="item.id">
                    <!-- 多选操作 -->
                    <view
                      class="td selection"
                      v-if="selection == 'mulit'"
                      :style="{
                        width: selectionTdWidth,
                        height: tdHeight + 'px',
                      }">
                      <view
                        :class="['td_wrap']"
                        :style="{
                          width: selectionTdWidth,
                          height: tdHeight + 'px',
                        }">
                        <checkbox
                          :value="checkBoxList[index].id"
                          :disabled="checkBoxList[index].$disabled"
                          :checked="checkBoxList[index].$checked"
                          style="transform: scale(0.7)" />
                      </view>
                    </view>
                    <template v-for="(tdItem, tdItemIndex) in columns">
                      <view
                        class="td"
                        :class="[
                          item.cellClassName && item.cellClassName[tdItem.key]
                            ? item.cellClassName[tdItem.key]
                            : '',
                          spanMethod(item, tdItem, index, tdItemIndex)[
                            'rowspan'
                          ] == 0
                            ? 'empty-cells-for-rowspan'
                            : '',
                          spanMethod(item, tdItem, index, tdItemIndex)[
                            'colspan'
                          ] == 0
                            ? 'empty-cells-for-celspan'
                            : '',
                          spanMethod(item, tdItem, index, tdItemIndex)[
                            'rowspan'
                          ] > 1
                            ? 'rowspan'
                            : '',
                          spanMethod(item, tdItem, index, tdItemIndex)[
                            'colspan'
                          ] > 1
                            ? 'colspan'
                            : '',
                        ]"
                        :style="{
                          height: countRowspanHeight(
                            item,
                            tdItem,
                            index,
                            tdItemIndex
                          ),
                          width: countColspanWidth(
                            item,
                            tdItem,
                            index,
                            tdItemIndex
                          ),
                        }"
                        :key="tdItem.key">
                        <view
                          :class="['td_wrap']"
                          :style="{
                            height: countRowspanHeight(
                              item,
                              tdItem,
                              index,
                              tdItemIndex
                            ),
                            width: countColspanWidth(
                              item,
                              tdItem,
                              index,
                              tdItemIndex,
                              true
                            ),
                          }">
                          <slot
                            :row="item"
                            v-if="slotCols.indexOf(tdItem.key) > -1"></slot>
                          <template v-if="tdItem.$operateList">
                            <template v-for="btn in tdItem.$operateList">
                              <button
                                :class="[btn.styles ? btn.styles : '']"
                                v-bind:style="{
                                  padding: '2px 5px',
                                  fontSize: '12px',
                                  lineHeight: '1.2',
                                  display: 'inline-block',
                                }"
                                @click="
                                  pullEvent(btn.event, {
                                    row: item,
                                    index: index,
                                  })
                                "
                                type="primary"
                                size="min"
                                :key="btn.id">
                                {{ btn.label }}
                              </button>
                            </template>
                          </template>
                          <template v-else>{{ item[tdItem.key] }}</template>
                        </view>
                      </view>
                    </template>
                  </view>
                </template>
              </checkbox-group>
            </view>
          </view>
        </template>
        <template v-else>
          <view
            class="table_tbody_box empty-data-body-box div-table-body"
            :style="{ height: talbeBodyHeight, width: emptyColWidth }">
            <view
              class="tr"
              :style="{ height: talbeBodyHeight, width: emptyColWidth }">
              <view
                class="td"
                :style="{ height: emptyColHeight, width: emptyColWidth }">
                <view
                  :class="['td_wrap']"
                  :style="{
                    height: parseInt(emptyColHeight - 2) + 'px',
                    width: emptyColWidth,
                    lineHeight: parseInt(emptyColHeight - 2) + 'px',
                  }">
                  <text @click="emptyClickCallBack">{{ emptyText }}</text>
                </view>
              </view>
            </view>
          </view>
        </template>
      </view>
    </view>
    <loading-component v-if="loading" />
  </view>
</template>

<script>
import loadingComponent from "./loading.vue";
export default {
  components: { loadingComponent },
  props: {
    //显示列
    columns: {
      type: Array,
      required: true,
    },
    //数据
    list: {
      type: Array,
      required: true,
    },
    //自定义行和列样式
    rowClassName: {
      type: [String, Function],
      default: "",
    },
    //自定义列元素
    "slot-cols": {
      type: Array,
      default: () => {
        return [];
      },
    },
    //行列合并函数
    "span-method": {
      type: Function,
      default: () => {
        return () => {
          return {
            rowspan: 1,
            colspan: 1,
          };
        };
      },
    },
    //是否可选  mulit=>多选   single=》单选
    selection: {
      type: String,
      default: "none",
    },
    loading: {
      type: Boolean,
      default: false,
    },
    height: {
      type: Number,
      default: undefined,
    },
    "td-width": {
      type: Number,
      default: 110,
    },
    "td-height": {
      type: Number,
      default: 30,
    },
    "th-td-height": {
      type: Number,
      default: 30,
    },
    "td-padding": {
      type: Number,
      default: 10,
    },
    "border-color": {
      type: String,
      default: "#666",
    },
    emptyText: {
      type: String,
      default: "数据为空",
    },
    //空提示点击事件
    emptyClickFn: {
      type: Function,
      default() {
        return () => {};
      },
    },
  },
  computed: {
    //表格高度
    tableHeight() {
      return Number(this.height) ? this.height + "px" : "auto";
    },
    //表格主体高度
    talbeBodyHeight() {
      let t =
        this.tableHeight !== "auto"
          ? parseInt(this.tableHeight) - this.tdHeight - 1 + "px"
          : "auto";
      return t;
    },
    //可选的列表长度
    allCheckBoxAbledLen() {
      return this.checkBoxList.filter((item) => !item.$disabled).length;
    },
    //没数据时候主体高度
    emptyColHeight() {
      return this.height ? this.height - this.thTdHeight + "px" : "100px";
    },
    //没数据时候，主体的宽度
    emptyColWidth() {
      let t = this.tdWidth * this.columns.length + "px";
      return t;
    },
  },
  data() {
    return {
      checkBoxList: [], //多选=》选中列表
      switchAllCheckBox: false, //多选=》全选
      selectionTdWidth: "50px", //多选列宽
      singleSelect: {}, //单选，选中行
    };
  },
  watch: {
    list() {
      this.asyncCheckBoxList();
    },
  },
  created() {
    this.asyncCheckBoxList();
  },
  methods: {
    //获取数据副本，轻拷贝
    asyncCheckBoxList() {
      this.checkBoxList = this.list.map((item) => {
        return { ...item };
      });
    },
    //自定义行样式
    rowClassNamePlus(row, index) {
      if (typeof this.rowClassName === "string") {
        return this.rowClassName;
      } else if (typeof this.rowClassName === "function") {
        return this.rowClassName(row, index);
      }
    },
    //事件触发
    pullEvent(event, data) {
      this.$emit(event, data);
    },
    /**
     * 计算单列宽
     * iswrap  是否是内容容器
     */
    countColspanWidth(item, tdItem, index, tdItemIndex, iswrap = false) {
      let borderLeft = iswrap && tdItemIndex > 0 ? 1 : 0;
      //是否跨列,返回跨列个数，1为不跨列
      let moreThanOne =
        this.spanMethod(item, tdItem, index, tdItemIndex) &&
        this.spanMethod(item, tdItem, index, tdItemIndex)["colspan"];
      //console.log(`第${index}行,第${tdItemIndex}列 是跨列么?${moreThanOne}`);
      let t =
        moreThanOne > 1
          ? moreThanOne * this.tdWidth - borderLeft + "px"
          : this.tdWidth - borderLeft + "px";
      //跨列
      if (moreThanOne > 1) {
        let countWidth = 0;
        for (let i = tdItemIndex; i < tdItemIndex + (moreThanOne - 1); i++) {
          countWidth +=
            this.columns[i].$width && parseInt(this.columns[i].$width)
              ? parseInt(moreThanOne * this.columns[i].$width) - borderLeft
              : this.tdWidth * moreThanOne;
        }
        return countWidth + "px";
      } else {
        //不跨列
        let tmp =
          this.columns[tdItemIndex].$width &&
          parseInt(this.columns[tdItemIndex].$width)
            ? parseInt(this.columns[tdItemIndex].$width)
            : this.tdWidth;
        return tmp + "px";
      }
      return t;
    },
    /**
     * 计算头部td的宽度
     * */
    countHeadColspanWidth(item, index, iswrap = false) {
      let borderLeft = iswrap && index > 0 ? 1 : 0;
      let tmp = item.$width ? parseInt(item.$width) : this.tdWidth;
      return tmp + "px";
    },
    /**
     * 计算单列高
     * */
    countRowspanHeight(item, tdItem, index, tdItemIndex) {
      //是否跨行
      let moreThanOne =
        this.spanMethod(item, tdItem, index, tdItemIndex) &&
        this.spanMethod(item, tdItem, index, tdItemIndex)["rowspan"] > 1;
      let t = moreThanOne
        ? this.spanMethod(item, tdItem, index, tdItemIndex)["rowspan"] *
            this.tdHeight +
          "px"
        : this.tdHeight + "px";
      return t;
    },
    /*
     * 单选行
     * */
    selectRow(item, index) {
      if (item.$disabled) {
        return;
      }
      this.checkBoxList = this.checkBoxList.map((sitem, sindex) => {
        if (index === sindex) {
          sitem.$checked = true;
        } else {
          sitem.$checked = false;
        }
        return sitem;
      });
      if (this.selection) {
        this.$emit("on-selection-change", {
          old: this.singleSelect,
          new: {
            index,
            item,
          },
        });
      }
      this.singleSelect = {
        index,
        item,
      };
    },
    /*
     * 多选
     * */
    checkboxChange(e) {
      let val = e.detail.value;
      let before = [];
      for (let v = 0; v < this.allCheckBoxAbledLen; v++) {
        if (this.checkBoxList[v].$checked === true) {
          before.push({ ...this.checkBoxList[v] });
        }
      }
      if (val.length == this.allCheckBoxAbledLen) {
        this.switchAllCheckBox = true;
        this.checkBoxList = this.checkBoxList.map((item) => {
          if (!item.$disabled) {
            item.$checked = true;
          }
          return item;
        });
      } else {
        this.switchAllCheckBox = false;
        this.checkBoxList = this.checkBoxList.map((item) => {
          if (val.indexOf(item.id) > -1) {
            item.$checked = true;
          } else {
            item.$checked = false;
          }
          return item;
        });
      }
      this.$emit("on-selection-change", {
        old: before,
        new: this.checkBoxList.filter((item) => item.$checked === true),
      });
    },
    /*
     * 全选
     * */
    checkboxChangeAll(e) {
      let val = e.detail.value;
      let before = [];
      for (let v = 0; v < this.allCheckBoxAbledLen; v++) {
        if (this.checkBoxList[v].$checked === true) {
          before.push({ ...this.checkBoxList[v] });
        }
      }
      if (val && val[0] == "all") {
        this.switchAllCheckBox = true;
        this.checkBoxList = this.checkBoxList.map((item) => {
          if (!item.$disabled) {
            item.$checked = true;
          }
          return item;
        });
      } else {
        this.switchAllCheckBox = false;
        this.checkBoxList = this.checkBoxList.map((item) => {
          item.$checked = false;
          return item;
        });
      }
      this.$emit("on-selection-change", {
        old: before,
        new: this.checkBoxList.filter((item) => item.$checked === true),
      });
    },
    /*
     * 空提示点击事件
     * */
    emptyClickCallBack() {
      typeof this.emptyClickFn == "function" ? this.emptyClickFn() : "";
    },
  },
};
</script>

<style lang="scss">
$div-table-border-color: #666;
$div-table-border-width: 1upx;
@mixin fixBorderWidth($dir: none) {
  @if $dir==none {
    @media screen and (-webkit-device-pixel-ratio: 1) {
      border-width: 1px;
    }
    @media screen and (-webkit-device-pixel-ratio: 2) {
      border-width: 0.5px;
    }
    @media screen and (-webkit-device-pixel-ratio: 3) {
      border-width: 0.5px;
    }
  } @else {
    @media screen and (-webkit-device-pixel-ratio: 1) {
      border-#{$dir}-width: 1px;
    }
    @media screen and (-webkit-device-pixel-ratio: 2) {
      border-#{$dir}-width: 0.5px;
    }
    @media screen and (-webkit-device-pixel-ratio: 3) {
      border-#{$dir}-width: 0.5px;
    }
  }
}
.no-bad-table-wrap {
  position: relative;
  overflow: hidden;
  //外层容器
  .table_box_big {
    overflow: auto;
    width: 100%;
    position: relative;
    // height: 350px;
  }
  //工具类
  .verticalV {
    position: absolute;
    width: 100%;
    text-align: center;
    left: 50%;
    top: 50%;
    transform: translateY(-50%);
  }

  .table_box {
    overflow: auto;
    // position: absolute;
  }

  .table_tbody_box {
    // height: 300px;
    // overflow: scroll;
  }

  //没有任何数据
  .empty-data-body-box {
    min-height: 100px;
    line-height: 100px;
    text-align: center;
    color: #666;
    border: 1px solid $div-table-border-color;
    @include fixBorderWidth;
    border-top: 0;
  }

  &.fix-height {
    .table_box_big {
      overflow-x: scroll;
      overflow-y: hidden;
      position: relative;

      // height: 350px;
    }

    .table_box {
      overflow: hidden;
      position: absolute;
    }

    .table_tbody_box {
      // height: 300px;
      overflow: scroll;
      border-bottom: 1px solid $div-table-border-color;
      @include fixBorderWidth(bottom);
    }

    //固定高低里面的内容表格底部不要边框
    .div-table-body {
      border-top: 0;
      border-bottom: 0;
      //固定高度，数据为空
      &.empty-data-body-box {
        border-bottom: $div-table-border-width solid $div-table-border-color;
        @include fixBorderWidth(bottom);
      }
    }
  }

  //头部表格
  .th,
  .thead .tr,
  .fixed-thead-tr {
    .td {
      background-color: #e0e0ea;

      .td_wrap {
        background-color: #e0e0ea;
      }
    }
  }

  //固定右边一列
  .fixed-right {
    position: absolute;
    top: 0upx;
    right: 0px;
    z-index: 100;
    // border-right: $div-table-border-width solid $div-table-border-color;
    // border-left: $div-table-border-width solid $div-table-border-color;
    box-shadow: -2px 0 5px rgba(0, 0, 0, 0.5);
  }

  //固定左边一列
  .fixed-left {
    position: absolute;
    top: 0upx;
    left: -1px;
    z-index: 100;
    border-right: $div-table-border-width solid $div-table-border-color;
    border-left: $div-table-border-width solid $div-table-border-color;
    @include fixBorderWidth(right);
    @include fixBorderWidth(left);
    box-shadow: 2px 0 5px rgba(0, 0, 0, 0.5);
  }

  .tr,
  .th {
    display: table-row;

    & + .tr,
    & + .th {
      .td,
      .th {
        border-top: $div-table-border-width solid $div-table-border-color;
        @include fixBorderWidth(top);
        word-break: break-word;
      }
    }
  }
  //外层容器控制td左右居中
  &.td-center {
    .td {
      .td_wrap {
        text-align: center;
      }
    }
  }
  .td {
    display: table-cell;
    vertical-align: middle;
    text-align: center;
    box-sizing: border-box;
    z-index: 1;
    position: relative;
    overflow: hidden;

    .td_wrap {
      position: relative;
      padding: 10upx;
      box-sizing: border-box;
      overflow: hidden;
      line-height: 20px;
      font-size: 12px;
      background: #fff;
      text-align: left;
    }

    &.colspan {
      z-index: 10;
      position: absolute;
      .td_wrap {
        width: 100%;
        height: 100%;
        left: 0;
        top: 0;
        position: absolute;
      }
    }

    &.rowspan {
      position: absolute;
      z-index: 10;
    }

    &.empty-cells-for-celspan {
      border-left: none !important;

      .td_wrap {
        opacity: 0;
      }
    }

    &.empty-cells-for-rowspan {
      border-top: none !important;

      .td_wrap {
        opacity: 0;
      }
    }

    &.noPadding {
      padding: 0;
    }

    & + .td {
      .td_wrap {
        border-left: $div-table-border-width solid $div-table-border-color;
        @include fixBorderWidth(left);
      }
    }
  }

  .th .td {
    font-weight: bold;
  }
  //单选样式========》选中
  .selected {
    .td {
      background-color: #d3e3ef;

      .td_wrap {
        background-color: #d3e3ef;
      }
    }
  }

  //单选样式===》禁用
  .disabled {
    .td {
      background-color: #f8f8f9;
      opacity: 0.6;
    }
  }

  .div-table {
    display: table;
    border: $div-table-border-width solid $div-table-border-color;
    @include fixBorderWidth;
    box-sizing: border-box;
    table-layout: fixed;
    position: relative;

    &.div-table-body {
      border-top: 0;
    }
    .tbody {
      display: table-row-group;
    }

    .thead {
      display: table-header-group;

      //       .tr,
      //       .th {
      //
      //         .td,
      //         .th {
      //           width: 120upx;
      //           height: 75px;
      //         }
      //       }
    }

    .colgroup {
      display: table-column-group;
    }

    .col {
      display: table-column;
    }

    .caption {
      display: table-caption;
    }
  }
}
.table_box_big {
  overflow-x: scroll;
  overflow-y: hidden;
  position: relative;
  height: 350px;
}

.table_box {
  overflow: hidden;
  position: absolute;
}

.table_tbody_box {
  height: 300px;
  overflow: scroll;
}

$div-table-border-color: #666;
$div-table-border-width: 1upx;

.div-table {
  display: table;
  border: $div-table-border-width solid $div-table-border-color;
  box-sizing: border-box;
  table-layout: fixed;
  position: relative;

  &.div-table-head {
    border-bottom: 0;
  }
  .tr,
  .th {
    display: table-row;

    & + .tr,
    & + .th {
      .td,
      .th {
        border-top: $div-table-border-width solid $div-table-border-color;
        word-break: break-word;
      }
    }
  }

  .td {
    display: table-cell;
    vertical-align: middle;
    text-align: center;
    box-sizing: border-box;
    z-index: 1;
    position: relative;
    .td_wrap {
      position: relative;
      width: 220upx;
      // height: 120upx;
      padding: 10upx;
      box-sizing: border-box;
      overflow: hidden;
      line-height: 1.6;
    }
    &.celspan {
      position: relative;
      width: 440upx;
      z-index: 10;
      position: absolute;
      .td_wrap {
        width: 100%;
        height: 100%;
        left: 0;
        top: 0;
        position: absolute;
      }
    }

    &.rowspan {
      position: absolute;
      // top: 0;
      // bottom: 0;
      width: 220upx;
      z-index: 10;
    }

    &.empty-cells {
      opacity: 0;
    }

    &.noPadding {
      padding: 0;
    }

    & + .td {
      border-left: $div-table-border-width solid $div-table-border-color;
    }
  }

  .th .td {
    font-weight: bold;
  }

  .tbody {
    display: table-row-group;
  }

  .thead {
    display: table-header-group;

    .tr,
    .th {
      .td,
      .th {
        // border-bottom: $div-table-border-width solid $div-table-border-color;
        width: 120upx;
        height: 75px;
      }
    }
  }

  .colgroup {
    display: table-column-group;
  }

  .col {
    display: table-column;
  }

  .caption {
    display: table-caption;
  }
}
</style>
